package state

import (
	"fmt"
	"strconv"

	"github.com/gomodule/redigo/redis"
	"github.com/ledgerwatch/log/v3"
)

type RedisConfig struct {
	network  string
	address  string
	password string
	redisKey string
}

const (
	delCmd    = "del"
	getCmd    = "get"
	lindexCmd = "lindex"
	llenCmd   = "llen"
	rpushCmd  = "rpush"
	setCmd    = "set"
)

func NewDefaultRedisConfig(redisKey string) *RedisConfig {
	return &RedisConfig{
		network:  "tcp",
		address:  "localhost:6379",
		password: "",
		redisKey: redisKey,
	}
}

func NewTestRedisConfig(redisKey string) *RedisConfig {
	return &RedisConfig{
		network:  "tcp",
		address:  "192.168.3.146:6379",
		password: "redis_local_lM2C4XYAoXdA",
		redisKey: redisKey,
	}
}

func (c *RedisConfig) LoadStatisticBlockNum() (uint64, error) {
	if c.redisKey == "" {
		return 0, fmt.Errorf("empty redis key")
	}

	conn, err := redis.Dial(c.network, c.address, redis.DialPassword(c.password))
	if err != nil {
		return 0, err
	}
	defer conn.Close()

	var rawGlobal interface{}
	if rawGlobal, err = conn.Do(getCmd, fmt.Sprintf("%s_%s", c.redisKey, "global")); err != nil {
		return 0, err
	}
	global, _ := strconv.ParseUint(string(rawGlobal.([]byte)), 10, 64)

	log.Info("Load redis for static", "content", global)

	return global, nil
}

func (c *RedisConfig) LoadStuckBlockNum() (uint64, error) {
	if c.redisKey == "" {
		return 0, fmt.Errorf("empty redis key")
	}

	conn, err := redis.Dial(c.network, c.address, redis.DialPassword(c.password))
	if err != nil {
		return 0, err
	}
	defer conn.Close()

	var rawGlobal interface{}
	if rawGlobal, err = conn.Do(getCmd, fmt.Sprintf("%s_%s", c.redisKey, "stuck")); err != nil {
		return 0, err
	}
	global, _ := strconv.ParseUint(string(rawGlobal.([]byte)), 10, 64)

	log.Info("Load redis for stuck", "content", global)

	return global, nil
}

func (c *RedisConfig) LoadStopBlockNum() (uint64, error) {
	if c.redisKey == "" {
		return 0, fmt.Errorf("empty redis key")
	}

	conn, err := redis.Dial(c.network, c.address, redis.DialPassword(c.password))
	if err != nil {
		return 0, err
	}
	defer conn.Close()

	var rawGlobal interface{}
	if rawGlobal, err = conn.Do(getCmd, fmt.Sprintf("%s_%s", c.redisKey, "stop")); err != nil {
		return 0, err
	}
	global, _ := strconv.ParseUint(string(rawGlobal.([]byte)), 10, 64)

	log.Info("Load redis for stop", "content", global)

	return global, nil
}

func (c *RedisConfig) StoreStatisticBlockNum(global uint64) error {
	if c.redisKey == "" {
		return fmt.Errorf("empty redis key")
	}

	conn, err := redis.Dial(c.network, c.address, redis.DialPassword(c.password))
	if err != nil {
		return err
	}
	defer conn.Close()

	if _, err := conn.Do(setCmd, fmt.Sprintf("%s_%s", c.redisKey, "global"), global); err != nil {
		return err
	}

	log.Info("Store redis for static", "content", global)

	return nil
}
